DivGrad ================= 计算逐元素除法 :math:`Y = x_1 / x_2` 的反向梯度。支持同形逐元素,以及 ``x1`` / ``x2`` 广播(一侧尺寸更大)的场景。 同形时: .. math:: \begin{aligned} dx_1 &= \frac{dy}{x_2} \\ dx_2 &= -\frac{dy \cdot x_1}{x_2^{2}} \end{aligned} 广播时,先在广播后的公共形状上按上式计算,再对较小输入一侧沿广播轴做 ReduceSum,使 ``dx1`` / ``dx2`` 与对应输入同形。 算子内部按 ``x1_size`` 与 ``x2_size`` 比较自动分发:``x1`` 更大、``x2`` 更大或两者相等。 输入: - **dy** - 上游梯度地址 - **x1_data** - 前向被除数地址 - **x2_data** - 前向除数地址 - **params** - ``Parameter`` 结构体地址,布局见下 - **core_mask** - 核掩码(仅共享存储版本使用) **Parameter 定义:** .. code-block:: c :linenos: typedef struct { void *tile_data0; // 临时工作空间 0,长度至少 dy_size 个元素 void *tile_data1; // 临时工作空间 1,长度至少 dy_size 个元素 void *tile_data2; // 临时工作空间 2,长度至少 dy_size 个元素 int *large_shape; // 较大输入形状,长度 ndims int *small_shape; // 较小输入形状,长度 ndims int *out_shape; // 输出 / dy 形状,长度 ndims long long ndims; // 维数 long long dy_size; // dy 元素个数 long long x1_size; // x1 元素个数 long long x2_size; // x2 元素个数 int *large_strides; // 较大输入 strides,长度 ndims int *small_strides; // 较小输入 strides,长度 ndims int *out_strides; // 输出 strides,长度 ndims int *large_multiples; // 较大输入广播倍数,长度 ndims int *small_multiples; // 较小输入广播倍数,长度 ndims int *indices; // 广播临时索引,长度 ndims,须清零 int *x1_shape; // x1 形状,长度 ndims int *x2_shape; // x2 形状,长度 ndims } Parameter; 输出: - **dx1** - 对 ``x1`` 的梯度,形状与 ``x1`` 相同 - **dx2** - 对 ``x2`` 的梯度,形状与 ``x2`` 相同 支持平台: ``FT78NE`` ``MT7004`` .. note:: - FT78NE 支持 fp32 - MT7004 支持 fp16、fp32 - ``tile_data0`` / ``tile_data1`` / ``tile_data2`` 各需至少 ``dy_size`` 个元素;fp32 为 ``dy_size * sizeof(float)`` 字节,fp16 为 ``dy_size * sizeof(float16)`` 字节 - ``*_strides`` / ``*_multiples`` 由算子内部使用,调用方分配长度 ``ndims`` 的 ``int`` 数组即可;``indices`` 长度 ``ndims``,须预先清零 - ``large_shape`` / ``small_shape`` / ``out_shape`` 按 ``x1_size``、``x2_size`` 关系设置:较大侧对应 ``large_shape``,``out_shape`` 取较大形状 **共享存储版本:** .. c:function:: void hp_div_grad_s(float16 *dy, float16 *dx1, float16 *dx2, float16 *x1_data, float16 *x2_data, Parameter *params, int core_mask) .. c:function:: void fp_div_grad_s(float *dy, float *dx1, float *dx2, float *x1_data, float *x2_data, Parameter *params, int core_mask) **C调用示例:** .. code-block:: c :linenos: :emphasize-lines: 40 // MT7004 示例(共享存储多核,DDR 地址) void TestDivGradSMCFp32(int core_mask) { int core_id = get_core_id(); int logic_core_id = GetLogicCoreId(core_mask, core_id); int core_num = GetCoreNum(core_mask); float *dy = (float *)0x81000000; float *dx1 = (float *)0x82000000; float *dx2 = (float *)0x83000000; float *x1_data = (float *)0x84000000; float *x2_data = (float *)0x85000000; float *tile0 = (float *)0x86000000; float *tile1 = (float *)0x87000000; float *tile2 = (float *)0x88000000; int *strides_base = (int *)0x8B000000; int x1_shape[4] = {4, 4, 4, 4}; int x2_shape[4] = {4, 4, 4, 4}; Parameter params; if (logic_core_id == 0) { params.tile_data0 = tile0; params.tile_data1 = tile1; params.tile_data2 = tile2; params.large_shape = x1_shape; params.small_shape = x2_shape; params.out_shape = x1_shape; params.ndims = 4; params.dy_size = 256; params.x1_size = 256; params.x2_size = 256; params.large_strides = strides_base; params.small_strides = strides_base + 4; params.out_strides = strides_base + 8; params.large_multiples = strides_base + 12; params.small_multiples = strides_base + 16; params.indices = strides_base + 20; params.x1_shape = x1_shape; params.x2_shape = x2_shape; memset(params.indices, 0, 4 * sizeof(int)); } sys_bar(0, core_num); fp_div_grad_s(dy, dx1, dx2, x1_data, x2_data, ¶ms, core_mask); } void main() { int core_mask = 0b1111; TestDivGradSMCFp32(core_mask); } **私有存储版本:** .. c:function:: void hp_div_grad_p(float16 *dy, float16 *dx1, float16 *dx2, float16 *x1_data, float16 *x2_data, Parameter *params) .. c:function:: void fp_div_grad_p(float *dy, float *dx1, float *dx2, float *x1_data, float *x2_data, Parameter *params) **C调用示例:** .. code-block:: c :linenos: :emphasize-lines: 34 // MT7004 示例(私有存储单核,AM 地址) void TestDivGradAMFp32(void) { float *dy = (float *)0x10010000; float *dx1 = (float *)0x10016000; float *dx2 = (float *)0x10020000; float *x1_data = (float *)0x10026000; float *x2_data = (float *)0x10030000; float *tile0 = (float *)0x10036000; float *tile1 = (float *)0x10040000; float *tile2 = (float *)0x10046000; int *strides_base = (int *)0x10050000; int x1_shape[4] = {4, 4, 4, 4}; int x2_shape[4] = {4, 4, 4, 4}; Parameter params; params.tile_data0 = tile0; params.tile_data1 = tile1; params.tile_data2 = tile2; params.large_shape = x1_shape; params.small_shape = x2_shape; params.out_shape = x1_shape; params.ndims = 4; params.dy_size = 256; params.x1_size = 256; params.x2_size = 256; params.large_strides = strides_base; params.small_strides = strides_base + 4; params.out_strides = strides_base + 8; params.large_multiples = strides_base + 12; params.small_multiples = strides_base + 16; params.indices = strides_base + 20; params.x1_shape = x1_shape; params.x2_shape = x2_shape; memset(params.indices, 0, 4 * sizeof(int)); fp_div_grad_p(dy, dx1, dx2, x1_data, x2_data, ¶ms); } void main() { TestDivGradAMFp32(); }